#include <msp430x26x.h>
#include <stdio.h>
#include "UART_HANDLER.h"

/******************************************************
 * CONSTANT DEFINES - define private constants for use in this module
 ******************************************************/
#define TX_BUFFER_SIZE 128
#define RX_BUFFER_SIZE 60
/******************************************************/

/******************************************************
 * INTERRUPT DECLARES - declare ISRs and link their handlers
 ******************************************************/
__interrupt void usart1_rx(void);  // UART RX interrupt
__interrupt void usart1_tx(void);  // UART TX interrupt
/******************************************************/

/******************************************************
Variable Declarations, initializations 
******************************************************/
struct UART_RX_BUF S_UART_BUFFER; //declare the RX buffer object to be used
struct UART_TX_BUF T_UART_BUFFER; //declare the TX buffer object to be used
unsigned char tx_buffer_ptr;
/*****************************************************/

/**************************************************
init_uart_tx_rx - fn initializes UART and TX and RX buffers
**************************************************/
void init_uart_tx_rx(void)
{
	int i; // Index variable
	
	//configure UCA1 (for GPS or debug terminal)
  	UCA1CTL0 = 0;						// 8N1 UART config
  	UCA1CTL1 |= (UCSSEL_2+UCSWRST);     // SMCLK source and hold UART in reset
  	UCA1BR0 = 13;                    	// see tables in user guide (115200 baud)
  	UCA1BR1 = 0;                    	// 
  	UCA1MCTL = UCOS16;      			// oversampling mode
  	UCA1CTL1 &= ~UCSWRST;             	// **Initialize USCI state machine**
  	UC1IE |= UCA1RXIE;                  // Enable USCI_A1 RX interrupt
    
 	// Initialize the RX & TX buffer structures (clear them)  
	for(i = 0; i < RX_BUFFER_SIZE; i++)
	{
		S_UART_BUFFER.Buffer[i]=0;
	}
	for(i = 0; i < TX_BUFFER_SIZE; i++)
	{
		T_UART_BUFFER.Buffer[i]=0;
	}
	S_UART_BUFFER.Buf_Strt = &S_UART_BUFFER.Buffer[0]; 	//get the address of the buffer head
	S_UART_BUFFER.Buf_End = &S_UART_BUFFER.Buffer[0];  	//get the address of the buffer tail
	S_UART_BUFFER.Buffer_Length = 0;					//initialize the buffer length to 0
	T_UART_BUFFER.Buf_Strt = &T_UART_BUFFER.Buffer[0]; 	//get the address of the buffer head
	T_UART_BUFFER.Buf_End = &T_UART_BUFFER.Buffer[0];  	//get the address of the buffer tail
	T_UART_BUFFER.Buffer_Length = 0;					//initialize the buffer length to 0
	tx_buffer_ptr = 0;                                  //initialize the tx pointer to 0
}
/*************************************************/

/**************************************************
tx_byte_to_slave - fn sends a single byte using UART0
**************************************************/
void tx_byte_to_slave(char Byte)
{
  	// Check TX buffer is not full before trying to add more data (drop overflow)
	if(T_UART_BUFFER.Buffer_Length < TX_BUFFER_SIZE)
	{
		T_UART_BUFFER.Buffer[T_UART_BUFFER.Buffer_Length] = Byte;	// Place data in buffer
		T_UART_BUFFER.Buffer_Length++;                              // increment buffer length
		UC1IE |= UCA1TXIE;                                          // Enable the USCI_A1 TX interrupt
	}
}
/*************************************************/

/**************************************************
tx_slave_string - function transmits a null terminated string pointed to by *Tx_string
**************************************************/
void tx_slave_string(char *Tx_string)
{
	// Walk through the whole string sending each character (byte) one by one
	while((*Tx_string) != '\0')
	{
		tx_byte_to_slave(*Tx_string++);
	}
}
/*************************************************/

/**************************************************
S_parseRXCmd - fn reads in serial commands and responds to them
**************************************************/
void S_parseRXCmd(void)
{
	if (S_UART_BUFFER.Buffer_Length > 0 && S_UART_BUFFER.Buffer[0] == '1')
	{
		// Stream measurements out
		tx_slave_string("Hello");
	}
	else if (S_UART_BUFFER.Buffer_Length > 0 && S_UART_BUFFER.Buffer[0] == '2')
	{
		// Stop any streaming measurements
		tx_slave_string("Goodbye");
	}
}

/********************************************************
ISR: usart0_rx - this code gets executed when USART1 receives a byte
********************************************************/
#pragma vector=USCIAB1RX_VECTOR
__interrupt void usart1_rx(void)
{
	//echo the byte out 
	tx_byte_to_slave(UCA1RXBUF);
	
	// If the RX buffer is not full, copy RXed byte into it
	if(S_UART_BUFFER.Buffer_Length < TX_BUFFER_SIZE)
	{
		S_UART_BUFFER.Buffer[S_UART_BUFFER.Buffer_Length] = UCA1RXBUF; // Copy Data
		S_UART_BUFFER.Buffer_Length++; // increment buffer length
	}
	else
	{
		S_UART_BUFFER.Buffer_Length = 0;  // reset buffer if we would have written past the end
	}  
}
/*******************************************************/

/********************************************************
ISR: usart0_tx - this code gets executed when USART1 TX buffer is empty
********************************************************/
#pragma vector=USCIAB1TX_VECTOR
__interrupt void usart1_tx(void)
{
	// If there are still bytes to be sent send a byte
	if (tx_buffer_ptr < T_UART_BUFFER.Buffer_Length)
	{
		UCA1TXBUF = T_UART_BUFFER.Buffer[tx_buffer_ptr++];
	}
	else
	{
		// We have flushed the buffer, clear the buffer, reset the TX data pointer
		tx_buffer_ptr = 0;
		T_UART_BUFFER.Buffer_Length = 0;
		
		// Also clear the interrupt enable so we don't have useless interrupts
		UC1IE &= ~UCA1TXIE;
	}
}
